package jalgebrava.group.morphisms;

import jalgebrava.group.Group;
import jalgebrava.group.GroupElement;
import jalgebrava.util.F;

public class Homomorphism<G, H> extends F<G,H> {
	private final Group<G> from;
	private final Group<H> to;
	private final F<G,H> f;
	public Homomorphism(Group<G> from, Group<H> to, F<G,H> f) {
		this.from = from;
		this.to = to;
		this.f = f;
		if (! isHomomorphism()) {
			throw new RuntimeException("Not a homomorphism");
		}
	}
	public final static<G,H> Homomorphism<G, H> mk(Group<G> from, Group<H> to, F<G,H> f) {
		return new Homomorphism<G, H>(from, to, f);
	}
	public final GroupElement<H> applyElement(GroupElement<G> x) {
		return to.element(f.apply(x.g));
	}
	@Override
	public final H apply(G x) {
		return f.apply(x);
	}
	public boolean isHomomorphism() {
		
		for (G x: from) {
			
			if (! to.contains(f.apply(x))) {
				throw new RuntimeException("image of " + x + " outside target group");
			}
			H fx = f.apply(x);
			for (G y: from) {
				
				G xy = from.mul(x, y);
				H f_xy = f.apply(xy);
				H fy = f.apply(y);
				H fx_fy = to.mul(fx,fy);
				if (! to.equals(f_xy, fx_fy)) {
					System.out.println("x = " + x + "; fx = " + fx);
					System.out.println("y = " + y + "; fy = " + fy);
					System.out.println("xy = " + xy + "; f_xy = " + f_xy);
					System.out.println("fx * fy = " +  fx_fy);
//					throw new RuntimeException("Does not distribute over multiplication");
					return false;
				}				
			}
		}
		return true;
	}
}
